<% if object.async -%>
<%
  op_path = path2navigate(object.async.operation.path)
  async_url = async_operation_url(object, object.async.operation.base_url)
  stat_path = path2navigate(object.async.status.path)
  check_interval = sprintf('%.1f', object.async.operation.wait_ms / 1000.0)
-%>
<%   if is_standard_async -%>
<%
  res_path = path2navigate(object.async.result.path)
  res_url = async_operation_url(object, object.async.result.base_url)
-%>
@link_wrapper
def resource_get_url(session, wait_done):
    combined = session.module.params.copy()
    combined['op_id'] = navigate_hash(wait_done, <%= res_path -%>)
<% if res_url.include? '{project}' -%>
<%=
  indent(send_request(
    "combined['project'] = session.get_project_id()",
    "", "session.module"
  ), 4)
%>

<% end-%>
    url = <%=quote_string(res_url)%>.format(**combined)

<%=
  indent(send_request(
    "endpoint = session.get_service_endpoint(\"#{object.service_type}\")",
    "", "session.module"
  ), 4)
%>

    return endpoint + url


<% end -%>
<%=
  lines(emit_link('async_op_url', async_url, object, true, object.async.operation.service_type || object.service_type), 2)
-%>
<%   if is_standard_async -%>
def wait_for_operation(session, op_result, timeout):
    op_id = navigate_hash(op_result, <%= op_path -%>)
    url = async_op_url(session, {'op_id': op_id})
    return wait_for_completion(session, url, timeout)


def wait_for_completion(session, url, timeout):
<%
  complete_states = object.async.status.complete.compact.map { |x| quote_string(x) }
  allowed_states = object.async.status.allowed.compact.map { |x| quote_string(x) }
  allowed_states = [allowed_states, complete_states].flatten
-%>
    module = session.module
    end = time.time() + timeout
    while time.time() <= end:
<%=
  indent(send_request(
    "op_result = session.get(url)",
    [
      "time.sleep(#{check_interval})",
      "continue"
    ]
  ), 8)
%>

        raise_if_errors(op_result, module)

        status = navigate_hash(op_result, <%= stat_path -%>)
        if status not in [<%= allowed_states.join(', ') -%>]:
            module.fail_json(msg="Invalid async operation status %s" % status)
        if status in [<%= complete_states.join(', ') -%>]:
            return op_result

        time.sleep(<%= check_interval %>)

    module.fail_json(msg="Timeout to wait for async operation to be completed")
<%   else # use get interface to retrieve the status -%>
<%     if object.async.status.allowed -%>
def wait_for_operation(session, op_result, timeout, complete_states, allowed_states):
    op_id = navigate_hash(op_result, <%= op_path -%>)
    url = async_op_url(session, {'op_id': op_id})
    return wait_for_completion(session, url, timeout, complete_states, allowed_states)


def wait_for_completion(session, op_uri, timeout, complete_states, allowed_states):
    module = session.module
    end = time.time() + timeout
    while time.time() <= end:
<%=
  indent(send_request(
    "op_result = session.get(op_uri)",
    [
      "time.sleep(#{check_interval})",
      "continue"
    ]
  ), 8)
%>

<%       if object.async.error -%>
        raise_if_errors(op_result, module)

<%       end -%>
        status = navigate_hash(op_result, <%= stat_path -%>)
        if status not in allowed_states:
            module.fail_json(msg="Invalid async operation status %s" % status)
        if status in complete_states:
            return op_result
        time.sleep(<%= check_interval %>)

    module.fail_json(msg="Timeout to wait completion")
<%     else # object.async.status.allowed -%>
def wait_for_operation(session, op_result, timeout, is_complete):
    op_id = navigate_hash(op_result, <%= op_path -%>)
    url = async_op_url(session, {'op_id': op_id})
    return wait_for_completion(session, url, timeout, is_complete)


def wait_for_completion(session, op_uri, timeout, is_complete):
    module = session.module
    end = time.time() + timeout
    while time.time() <= end:
<%=
  indent(send_request(
    "op_result = session.get(op_uri)",
    [
      "time.sleep(#{check_interval})",
      "continue"
    ]
  ), 8)
%>

<%       if object.async.error -%>
        raise_if_errors(op_result, module)

<%       end -%>
        if is_complete(op_result):
            return op_result
        time.sleep(<%= check_interval %>)

    module.fail_json(msg="Timeout to wait completion")
<%     end # object.async.status.allowed -%>
<%     if (object.async.async_methods.nil? || object.async.async_methods.include?("delete")) -%>


def wait_for_delete(session, link, timeout):
    end = time.time() + timeout
    while time.time() <= end:
<%=
  indent(send_request("session.get(link)", "pass", "", "return"), 8)
%>

        time.sleep(<%= check_interval %>)

    session.module.fail_json(msg="Timeout to wait for deletion to be completed")
<%     end -%>
<%   end # is_standard_async -%>
<%   if object.async.error -%>


def raise_if_errors(response, module):
<%
  err_path = path2navigate(object.async.error.path)
  err_msg = path2navigate(object.async.error.message)
-%>
    failed = navigate_hash(response, <%= err_path -%>)
    if failed:
        module.fail_json(msg=navigate_hash(response, <%= err_msg -%>))
<%   end # object.async.error -%>
<% end # object.async -%>
